home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 February: Tool Chest / Dev.CD Feb 94.toast / New System Software Extensions / QuickDraw™ GX v1.0ß2 / Sample Code / Printing Samples / Extensions… / UserItems extension ƒ / UserItems.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-09-09  |  11.7 KB  |  450 lines  |  [TEXT/MPS ]

  1. /*________________________________________________________
  2.  
  3.     File: UserItems.c
  4.  
  5.     C code for a printing extension that shows how
  6.     to handle hits and updates for userItems in panels.
  7.  
  8.     Dave Hersey
  9.     Apple Developer Technical Support
  10.  
  11.     06/06/93 - dmh - Created.
  12.     09/07/93 - dmh - Updated to b2.
  13.  
  14.     (Note: all functions are in the Mark menu.)
  15.     
  16. __________________________________________________________*/
  17.  
  18. #include "UserItems.h"
  19.  
  20.  
  21. MyGlobalRec        gl;        // Global data used by our extension.
  22.  
  23.  
  24. /*******************************************************************
  25.     InitGlobalData is used to initialize any global data we need to
  26.     in our initialize message override.  It's critical that you do
  27.     things this way, rather than access the data in the same scope
  28.     that you call NewMessageGlobals.  Otherwise, some compilers
  29.     will give you code that references an invalid a5 world.
  30.  
  31. ********************************************************************/
  32.  
  33. OSErr InitGlobalData()
  34. {
  35. // Initialize any global data here.
  36.     
  37.     gl.panelPict = nil;
  38.     return noErr;
  39. }
  40.  
  41.  
  42. /*******************************************************************
  43.     NewInitialize is our override for the Initialize message.  In
  44.     here, you shouldn't initialize anything directly-- call
  45.     InitGlobalData for that.  Once you create the A5 world with
  46.     NewMessageGlobals, you can access your global data just like
  47.     you were an app.  Whenever you're called, your global data will
  48.     be valid.
  49.     
  50. ********************************************************************/
  51.  
  52. OSErr NewInitialize()
  53. {
  54.     OSErr    err;
  55.  
  56. // Create an A5 world, and initialize our global data.
  57.  
  58.     err = NewMessageGlobals(A5Size(), A5Init);
  59.     
  60.     if (!err) err = InitGlobalData();
  61.     
  62.     return err;
  63. }
  64.  
  65.  
  66. /*******************************************************************
  67.     NewShutDown is our override for the GXShutDown message.  We
  68.     simply throw away our a5 world.
  69.     
  70. ********************************************************************/
  71.  
  72. OSErr NewShutDown()
  73. {
  74.     DisposeMessageGlobals();
  75.     return noErr;
  76. }
  77.  
  78.  
  79. /*******************************************************************
  80.     NewJobPrintDialog is our override for GXJobPrintDialog.  All
  81.     we do is set up our panel and then forward the message.
  82.     
  83. ********************************************************************/
  84.  
  85. OSErr NewJobPrintDialog(gxDialogResult *dlogResult)
  86. {
  87.     SetUpPrintPanel();
  88.     return Forward_GXJobPrintDialog(dlogResult);
  89. }
  90.  
  91.  
  92. /*******************************************************************
  93.     NewHandlePanelEvent is our override for GXHandlePanelEvent. If
  94.     the event is one of ours, we handle it, otherwise we just
  95.     forward it down the chain.
  96.     
  97. ********************************************************************/
  98.  
  99. OSErr NewHandlePanelEvent(gxPanelInfoRecord *panelInfo)
  100. {
  101.     OSErr            err = noErr;
  102.     GrafPtr            oldPort;
  103.     DialogPtr        pDlg;
  104.     short            oldResFile;
  105.  
  106. // Get a pointer to the dialog, save our current grafPort,
  107. // and set us to the dialog's port.
  108.  
  109.     pDlg = panelInfo->pDlg;
  110.     GetPort(&oldPort);
  111.     SetPort(pDlg);
  112.  
  113.     switch (panelInfo->panelEvt)
  114.     {
  115.         case gxPanelOpenEvt:            // Initialize and draw
  116.                                         // Load the user item picture.
  117.             oldResFile = CurResFile();
  118.             UseResFile(GXGetMessageHandlerResFile());
  119.             gl.panelPict = GetPicture(r_ExtensionPanel);
  120.             UseResFile(oldResFile);
  121.             break;
  122.  
  123.         case gxPanelCloseEvt:            // Your panel is going away (panel switch,
  124.                                         // confirm or cancel)
  125.             if (gl.panelPict)
  126.                 ReleaseResource((Handle) gl.panelPict);
  127.             
  128.             break;
  129.     }
  130.  
  131. // Restore the original port as we leave.
  132.  
  133.     SetPort(oldPort);
  134.     return err;
  135. }
  136.  
  137.  
  138. /*******************************************************************
  139.     NewFilterPanelEvent is a routine to filter update events in our
  140.     panel, and update our userItems accordingly.
  141.  
  142. ********************************************************************/
  143.  
  144. OSErr NewFilterPanelEvent(gxPanelInfoRecord *panelInfo, Boolean *returnImmed)
  145. {
  146.     OSErr        err = noErr;
  147.     DialogPtr    pDlg;
  148.     WindowPtr    theWindow;
  149.     short        thePart, theItem;
  150.     Point        thePt;
  151.  
  152. // Get a pointer to the dialog, save our current grafPort,
  153. // and set us to the dialog's port.
  154.  
  155.     pDlg = panelInfo->pDlg;
  156.  
  157.     switch (panelInfo->panelEvt)
  158.     {
  159.         case gxPanelFilterEvt:
  160.         
  161.             switch (panelInfo->theEvent->what)
  162.             {
  163.                 case updateEvt:        // look for, and handle, our update events.
  164.  
  165.                     if ((WindowPtr) panelInfo->theEvent->message == pDlg)
  166.                         err = HandlePanelUpdate(pDlg, panelInfo);
  167.  
  168.                     break;
  169.  
  170.                 case mouseDown:        // look for our dialog item hits.
  171.                                     // If we're not the front window, ignore hits.
  172.  
  173.                     require((pDlg == FrontWindow()), NotFrontWindow);
  174.                     thePart = FindWindow(panelInfo->theEvent->where, &theWindow);
  175.                     require(((theWindow == pDlg) && (thePart == inContent)), NotForUs);
  176.  
  177.                     thePt = panelInfo->theEvent->where;
  178.                     GlobalToLocal(&thePt);
  179.                     theItem = FindDItem(pDlg, thePt);
  180.  
  181.                                     // FindDItem == -1 if the point lies outside the dialog.
  182.                                     // Unless theItem == -1, go handle the hit.
  183.  
  184.                     if (theItem != -1)
  185.                         err = HandlePanelHit(pDlg, panelInfo, theItem +1, returnImmed);
  186.  
  187. NotForUs:
  188. NotFrontWindow:
  189.                     break;
  190.             }
  191.     }
  192.  
  193.     return err;
  194. }
  195.  
  196.  
  197. /*******************************************************************
  198.     HandlePanelUpdate is a routine to update our panel's userItems.
  199.     Note that we don't pass this routine to the Dialog Manager,
  200.     we only get here by way of our panel event handler.  This
  201.     assures that we can access our global data, and that our
  202.     resource file is open.  In this example, we draw from a global
  203.     PicHandle, to show that our globals are intact.
  204.     
  205.     NOTE: With the exception of the code below that's marked:
  206.     
  207.                "YOU SHOULD CHANGE THE FOLLOWING…"
  208.     
  209.     you can just use this code verbatim, regardless of the number
  210.     or purpose of your dialog's userItems.
  211.     
  212. ********************************************************************/
  213.  
  214. OSErr HandlePanelUpdate(DialogPtr theDialog, gxPanelInfoRecord *panelInfo)
  215. {
  216.     GrafPtr        oldPort;
  217.     OSErr        err;
  218.     Rect        theClipRect, myUserItemRect;
  219.     RgnHandle    tempRgn, oldVis;
  220.     Point        top;
  221.     short        dx, dy, itemKind;
  222.     Handle        itemHdl;
  223.  
  224. // Create a new region handle.  If we can't do that, return an error.
  225.  
  226.     tempRgn = NewRgn();
  227.     require_action(tempRgn, CanNotCreateRgn, err = MemError(););
  228.  
  229.  
  230. // Copy the window's update region to our temporary region handle,
  231. // then adjust the region so that it's correctly aligned with our
  232. // window.  Finally, intersect this region with the window's visRgn.
  233.  
  234.     CopyRgn(((DialogPeek) theDialog)->window.updateRgn, tempRgn);
  235.     top = *(Point *) &(*tempRgn)->rgnBBox.top;
  236.     GlobalToLocal(&top);
  237.     dx = (*tempRgn)->rgnBBox.left - top.h;
  238.     dy = (*tempRgn)->rgnBBox.top - top.v;
  239.     OffsetRgn(tempRgn, -dx, -dy);
  240.     SectRgn(theDialog->visRgn, tempRgn, tempRgn);
  241.  
  242.     nrequire((err = MemError()), CanNotCopyRgn);
  243.  
  244.  
  245. // Now, get the various bounds rects of your userItems and
  246. // see if any fall within the update area.  If not, don't
  247. // bother drawing anything.
  248. //
  249. // NOTE: YOU SHOULD CHANGE THE FOLLOWING CODE to account for
  250. // for all of your userItems.  We only have one userItem in
  251. // this example.
  252.  
  253.     GetDItem(theDialog, panelInfo->itemCount + kMyUserItem, &itemKind,
  254.              &itemHdl, &myUserItemRect);
  255.  
  256.     theClipRect = (*tempRgn)->rgnBBox;
  257.     
  258.     if (SectRect(&myUserItemRect, &theClipRect, &theClipRect))
  259.     {
  260.  
  261. // Save the current visRgn, and store our temporary region as the new
  262. // visRgn.  This is similar to what happens when BeginUpdate is called.
  263. // When we draw, only pixels that fall in the update area (clipped to
  264. // the window's clipRgn) will be drawn.  This keeps us from doing
  265. // unnecessary redrawing, which would cause flashing and wasted cycles.
  266.  
  267.         oldVis = theDialog->visRgn;
  268.         theDialog->visRgn = tempRgn;
  269.  
  270.  
  271. // Save the current port, change it to the dialog's port, draw any
  272. // userItems that need updating, validate their areas and restore
  273. // the old visRgn and grafPort.
  274. //
  275. // NOTE: YOU SHOULD CHANGE THE FOLLOWING CODE to redraw and validate
  276. // any of your userItems which intersect the update region.  We only
  277. // have one userItem in this example.
  278.  
  279.         GetPort(&oldPort);
  280.         SetPort(theDialog);
  281.  
  282.         DrawPicture(gl.panelPict, &myUserItemRect);
  283.         ValidRect(&myUserItemRect);
  284.                 
  285.         theDialog->visRgn = oldVis;
  286.         SetPort(oldPort);
  287.     }
  288.  
  289. // Throw away our temporary region, and return any error.
  290.  
  291. CanNotCopyRgn:
  292.     DisposeRgn(tempRgn);
  293.  
  294.  
  295. CanNotCreateRgn:
  296.     
  297.     return err;
  298. }
  299.  
  300.  
  301. /*******************************************************************
  302.     HandlePanelHit is a routine to handle mouse hits in a panel's
  303.     userItem fields.  In this sample, we simply invert our userItem
  304.     whenever it's clicked in, and set returnImmed to true,
  305.     indicating that this event has been processed.
  306.     
  307. ********************************************************************/
  308.  
  309. OSErr HandlePanelHit(DialogPtr theDialog, gxPanelInfoRecord *panelInfo,
  310.                      short theItem, Boolean *returnImmed)
  311. {
  312.     GrafPtr        oldPort;
  313.     OSErr        err = noErr;
  314.     short        itemKind;
  315.     Rect        itemRect;
  316.     Handle        itemHdl;
  317.  
  318. // Save the current grafPort, set the current port to the dialog,
  319. // handle our panel hits, and restore the current port.
  320.  
  321.     GetPort(&oldPort);
  322.     SetPort(theDialog);
  323.  
  324.     switch (theItem - panelInfo->itemCount)
  325.     {
  326.  
  327. // Flash our userItem if it's hit.
  328.  
  329.         case kMyUserItem:
  330.  
  331.             GetDItem(theDialog, theItem, &itemKind, &itemHdl, &itemRect);
  332.             InvertRect(&itemRect);
  333.             while (StillDown());
  334.             InvertRect(&itemRect);
  335.  
  336.             *returnImmed = true;
  337.             break;
  338.             
  339.         /*    Code for handling other userItems would follow.
  340.             .
  341.             .
  342.             .
  343.         */
  344.  
  345.     }
  346.  
  347.     SetPort(oldPort);
  348.     return err;
  349. }
  350.  
  351.  
  352. /*******************************************************************
  353.     SetUpPrintPanel sets up our print panel, adding a default
  354.     ExtensionCollection item to the job collection.  This
  355.     collection item has the values we'll use to set up our panel's
  356.     controls.
  357.     
  358. ********************************************************************/
  359.  
  360. OSErr SetUpPrintPanel()
  361. {
  362.     OSErr                    err;
  363.     gxPanelSetupRecord        panelSetupRec;
  364.     ExtensionCollection        extConfig;
  365.  
  366. // Try to find our collection item.
  367.  
  368.     err = GetCollectionItem(GXGetJobCollection(GXGetJob()),
  369.                             kExtensionCollectionType,
  370.                             gxPrintingTagID,
  371.                             nil,
  372.                             &extConfig);
  373.  
  374.  
  375. // If we don't have an item in the job collection yet, store our default
  376. // settings in it.
  377.  
  378.     if (err == collectionItemNotFoundErr)
  379.     {
  380.         extConfig.extTurnedOn = kDefaultSetting;
  381.     
  382.         err = StoreJobCollectionItem(&extConfig, sizeof(ExtensionCollection),
  383.                                      kExtensionCollectionType, gxPrintingTagID,
  384.                                      true);
  385.  
  386.         nrequire(err, HaveCollectionMgrError);
  387.     }
  388.  
  389.  
  390. // Now, set up the panel.
  391.  
  392.     panelSetupRec.panelResId        = r_ExtensionPanel;        // which panel resource?
  393.     panelSetupRec.resourceRefNum    = GXGetMessageHandlerResFile(); // where is it?
  394.     panelSetupRec.refCon            = 0;                       // we don't use this.
  395.     panelSetupRec.panelKind            = gxExtensionPanel;     // This is an extension panel.
  396.  
  397.     err = GXSetupDialogPanel(&panelSetupRec);
  398.  
  399.  
  400. HaveCollectionMgrError:
  401.     
  402.     return err;
  403. }
  404.  
  405.  
  406. /*******************************************************************
  407.     StoreJobCollectionItem is a generic routine that stores a
  408.     collection item in the job collection.  If newItem is true,
  409.     a new collection item is added.  If it is false, an existing
  410.     one is replaced.
  411.     
  412. ********************************************************************/
  413.  
  414. OSErr StoreJobCollectionItem(void *collectItem, long collectSize, OSType collectType,
  415.                              short collectID, Boolean newItem)
  416. {
  417.     OSErr        err;
  418.     Collection    jobCollection;
  419.     long        index, itemSize, attributes;
  420.  
  421. // Get the job collection.  If we're adding a new collection item, do so.
  422. // Otherwise, get the existing item's index and replace the old collection
  423. // item.
  424.  
  425.     jobCollection = GXGetJobCollection(GXGetJob());
  426.  
  427.     if (newItem)
  428.         err = AddCollectionItem(jobCollection,
  429.                                 collectType,
  430.                                 collectID,
  431.                                 collectSize,
  432.                                 collectItem);
  433.     else
  434.     {
  435.         err = GetCollectionItemInfo(jobCollection,
  436.                                     collectType,
  437.                                     collectID,
  438.                                     &index,
  439.                                     &itemSize,
  440.                                     &attributes);
  441.         if (!err)
  442.             err = ReplaceIndexedCollectionItem(jobCollection,
  443.                                                index,
  444.                                                collectSize,
  445.                                                collectItem);
  446.     }
  447.  
  448.     return err;
  449. }
  450.